package aiingames.simulation.io;

import java.io.IOException;

import org.geotools.feature.Feature;
import org.matsim.core.utils.gis.ShapeFileReader;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;


import aiingames.simulation.network.Network;
import aiingames.simulation.network.Node;

public class NetworkReader {
	
	private static final double THRESHOLD = 1;
	private Network network;
	private String shapeFile;
	
	public NetworkReader(String shapeFile) {
		this.shapeFile = shapeFile;
	}

	public Network loadNetwork() {
		
		
		ShapeFileReader sr = new ShapeFileReader();
		try {
			sr.readFileAndInitialize(this.shapeFile);
		} catch (IOException e1) {
			throw new RuntimeException(e1);
		}
		
		this.network = new Network(sr.getBounds());
		for (Feature ft :sr.getFeatureSet()) {
			Geometry geo = ft.getDefaultGeometry();
			if (geo instanceof LineString) {
				createNode((LineString)geo);
			} else if (geo instanceof MultiLineString) {
				for (int i = 0; i < geo.getNumGeometries(); i++) {
					LineString ls = (LineString)geo.getGeometryN(i);
					createNode(ls);
				}
			}
		}
		

		for (Feature ft :sr.getFeatureSet()) {
			Geometry geo = ft.getDefaultGeometry();
			if (geo instanceof LineString) {
				createLink((LineString)geo);
			} else if (geo instanceof MultiLineString) {
				for (int i = 0; i < geo.getNumGeometries(); i++) {
					LineString ls = (LineString)geo.getGeometryN(i);
					createLink(ls);
				}
			}
		}
		
		return this.network;
	}

	private void createLink(LineString ls) {
		Node from = this.network.getNearestNode(ls.getStartPoint().getCoordinate());
		Node to = this.network.getNearestNode(ls.getEndPoint().getCoordinate());
		this.network.createLink(from, to);
		this.network.createLink(to, from);
	}

	private void createNode(LineString geo) {
		Coordinate c1 = geo.getStartPoint().getCoordinate();
		Node tmp1 = this.network.getNearestNode(c1);
		if (tmp1 == null || tmp1.getCoordinate().distance(c1) > THRESHOLD) {
			this.network.createNode(c1);
		}
		
		Coordinate c2 = geo.getEndPoint().getCoordinate();
		Node tmp2 = this.network.getNearestNode(c2);
		if (tmp2.getCoordinate().distance(c2) > THRESHOLD) {
			this.network.createNode(c2);
		}
	}
}
